#ifdef _MSC_VER
#include <windows.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "ram.h"

static int BYTE_ARR_size = 0;
static BYTE_ARR arrByte[50];
static int arrBytePos = 0;

#define PTR_WORK_FRAME ((unsigned char *)0xAB)

BYTE_ARR *BYTE_ARR_calloc(int size1, int size2)
{
	BYTE_ARR *ret = &arrByte[BYTE_ARR_size];
	
	ret->startpos = arrBytePos;
	ret->maxsize = size1 * size2;
	ret->memptr = NULL;

	BYTE_ARR_size++;
	arrBytePos += size1 * size2;

	if (BYTE_ARR_size >= sizeof(arrByte) / sizeof(arrByte[0]))
	{
#ifdef _MSC_VER
		exit(-1);
#else
		while(1);
#endif
	}

#ifdef _MSC_VER
	OutputDebugString("BYTE_ARR_calloc\n");
#endif

	return ret;
}

extern BYTE_ARR *BYTE_ARR_calloc_from(unsigned char *mem)
{
	BYTE_ARR *ret = &arrByte[BYTE_ARR_size];
	
	ret->startpos = 0;
	ret->maxsize = 0;
	ret->memptr = mem;
	
	BYTE_ARR_size++;
	
	if (BYTE_ARR_size >= sizeof(arrByte) / sizeof(arrByte[0]))
	{
#ifdef _MSC_VER
		exit(-1);
#else
		while(1);
#endif
	}

#ifdef _MSC_VER
	OutputDebugString("BYTE_ARR_calloc_from\n");
#endif

	return ret;
}

BYTE_ARR *BYTE_ARR_clone(BYTE_ARR *arr)
{
	BYTE_ARR *ret = &arrByte[BYTE_ARR_size];
	
	ret->startpos = arr->startpos;
	ret->maxsize = arr->maxsize;
	ret->memptr = arr->memptr;
	
	BYTE_ARR_size++;
	
	if (BYTE_ARR_size >= sizeof(arrByte) / sizeof(arrByte[0]))
	{
#ifdef _MSC_VER
		exit(-1);
#else
		while(1);
#endif
	}

#ifdef _MSC_VER
	OutputDebugString("BYTE_ARR_clone\n");
#endif

	return ret;
}

BYTE_ARR *BYTE_ARR_clone_from(BYTE_ARR *arr, int addr)
{
	BYTE_ARR *ret = &arrByte[BYTE_ARR_size];
	
	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		ret->startpos = arr->startpos;
		ret->maxsize = arr->maxsize;
		ret->memptr = arr->memptr + addr;
	}
	else
	{
		ret->startpos = arr->startpos + addr;
		ret->maxsize = arr->maxsize;
		ret->memptr = arr->memptr;
	}

	BYTE_ARR_size++;
	
	if (BYTE_ARR_size >= sizeof(arrByte) / sizeof(arrByte[0]))
	{
#ifdef _MSC_VER
		exit(-1);
#else
		while(1);
#endif
	}

#ifdef _MSC_VER
	if (BYTE_ARR_size > sizeof(arrByte) / sizeof(arrByte[0]) - 5)
	{
		OutputDebugString("warning....\n");
	}
	OutputDebugString("BYTE_ARR_clone_from\n");
#endif

	return ret;
}

void BYTE_ARR_clone_from2(BYTE_ARR *target, BYTE_ARR *arr, int addr)
{
	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		target->startpos = arr->startpos;
		target->maxsize = arr->maxsize;
		target->memptr = arr->memptr + addr;
	}
	else
	{
		target->startpos = arr->startpos + addr;
		target->maxsize = arr->maxsize;
		target->memptr = arr->memptr;
	}
}

int BYTE_ARR_equals(BYTE_ARR *arr, BYTE_ARR *arr2)
{
	return arr->maxsize == arr2->maxsize &&
		arr->memptr == arr2->memptr &&
		arr->startpos == arr2->startpos;
}

void BYTE_ARR_plus(BYTE_ARR *arr, int inc)
{
	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		arr->memptr += inc;
	}
	else
	{
		arr->startpos += inc;
	}
}

int BYTE_ARR_minus(BYTE_ARR *arr, BYTE_ARR *arr2)
{
	if (arr->memptr == NULL && arr2->memptr != NULL)
	{
#ifdef _MSC_VER
		exit(-1);
#else
		while(1);
#endif
	}
	if (arr->memptr != NULL && arr2->memptr == NULL)
	{
#ifdef _MSC_VER
		exit(-1);
#else
		while(1);
#endif
	}


	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		return arr->memptr - arr2->memptr;
	}
	else
	{
		return arr->startpos - arr2->startpos;
	}
}

unsigned char BYTE_ARR_Get(BYTE_ARR *arr, int addr)
{
	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		return arr->memptr[addr];
	}
	else
	{
		unsigned char ret = 0;
		Mem_Read(&ret, arr->startpos+addr, sizeof(ret));
		return ret;
	}
}

unsigned long BYTE_ARR_GetDWord(BYTE_ARR *arr, int addr)
{
	unsigned long ret = 0;
	ret |= BYTE_ARR_Get(arr, addr*4+0) << 0;
	ret |= BYTE_ARR_Get(arr, addr*4+1) << 8;
	ret |= BYTE_ARR_Get(arr, addr*4+2) << 16;
	ret |= BYTE_ARR_Get(arr, addr*4+3) << 24;
	return ret;
}

void BYTE_ARR_Set(BYTE_ARR *arr, int addr, unsigned char val)
{
	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		arr->memptr[addr] = val;
	}                    
	else
	{
		unsigned char ret = val;
		Mem_Write(&ret, arr->startpos+addr, sizeof(ret));
	}
}

void BYTE_ARR_SetWord(BYTE_ARR *arr, int addr, unsigned short val)
{
	BYTE_ARR_Set(arr, addr*2, (unsigned char)(val & 0xff));
	BYTE_ARR_Set(arr, addr*2+1, (unsigned char)((val >> 8) & 0xff));
}

unsigned short BYTE_ARR_GetWord(BYTE_ARR *arr, int addr)
{
	unsigned short ret = 0;
	ret |= BYTE_ARR_Get(arr, addr*2+0) << 0;
	ret |= BYTE_ARR_Get(arr, addr*2+1) << 8;
	return ret;
}

void BYTE_ARR_memset(BYTE_ARR *arr, int addr, unsigned char val, int size)
{
	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		memset(arr->memptr + addr, val, size);
	}
	else
	{
#ifdef _MSC_VER 
		//FIXME:
		int i;
		for (i = 0; i < size; ++i)
		{
			BYTE_ARR_Set(arr, addr+i, val);
		}
#endif
	}
}

void BYTE_ARR_memcpy(unsigned char *mem, BYTE_ARR *arr, int addr, int size)
{
	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		memcpy(mem, arr->memptr + addr, size);
	}
	else
	{
		Mem_Read(mem, arr->startpos+addr, size);
	}
}

//------------------------------------------------------------

void BYTE_ARR_clone_from2_work(BYTE_ARR *target, BYTE_ARR *arr, int addr)
{
	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		target->startpos = arr->startpos;
		target->maxsize = arr->maxsize;
		target->memptr = arr->memptr + addr;
	}
	else
	{
		target->startpos = arr->startpos + addr;
		target->maxsize = arr->maxsize;
		target->memptr = arr->memptr;
	}
}

void BYTE_ARR_plus_work(BYTE_ARR *arr, int inc)
{
	if (arr->memptr != NULL && arr->memptr != PTR_WORK_FRAME)
	{
		arr->memptr += inc;
	}
	else
	{
		arr->startpos += inc;
	}
}


unsigned short BYTE_ARR_GetWord_work(BYTE_ARR *arr, int addr)
{
#if !NO_WORKFRAME
    return BYTE_ARR_GetWord(arr, addr);
#else
	return 0;
#endif
}

BYTE_ARR *BYTE_ARR_calloc_work(int size1, int size2)
{
#if !NO_WORKFRAME
	return BYTE_ARR_calloc(size1, size2);
#else
	BYTE_ARR *ret = &arrByte[BYTE_ARR_size];
	
	ret->startpos = 0;
	ret->maxsize = size1 * size2;
	ret->memptr = PTR_WORK_FRAME;

	BYTE_ARR_size++;

	return ret;
#endif
}

void BYTE_ARR_memsetword_work(BYTE_ARR *arr, int addr, unsigned char val, int size)
{
	int i;
	for (i = 0; i < size; ++i)
	{
		BYTE_ARR_SetWord_work(arr, addr+i, val);
	}
}


//https://blog.csdn.net/iteye_4515/article/details/81800882
#define RGB565toRGB(rgb565)    ((DWORD)(((BYTE)((((rgb565)&0xF800)>>11)<<3)|((WORD)((BYTE)((((rgb565)&0x07E0)>>5)<<2))<<8))|(((DWORD)(BYTE)(((rgb565)&0x001F)<<3))<<16)))
#define RGB555toRGB(rgb555)    ((DWORD)(((BYTE)(((rgb555)>>7)&0xF8)|((WORD)((BYTE)(((rgb555)>>2)&0xF8))<<8))|(((DWORD)(BYTE)(((rgb555)<<3)&0xF8))<<16)))
#define RGBtoRGB565(rgb) ((WORD)(((((WORD)((rgb)>>3))&(0x1F))<<11)|((((WORD)((rgb)>>10))&(0x3F))<<5)|(((WORD)((rgb)>>19))&(0x1F))))

#ifndef _MSC_VER
#define USE_565
	
#ifndef DWORD
typedef unsigned long  DWORD;
#endif /* !DWORD */

#ifndef WORD
typedef unsigned short WORD;
#endif /* !WORD */

#ifndef BYTE
typedef unsigned char  BYTE;
#endif /* !BYTE */
	
#endif

void BYTE_ARR_SetWord_work(BYTE_ARR *arr, int addr, unsigned short val)
{
#if !NO_WORKFRAME
	BYTE_ARR_SetWord(arr, addr, val);
#else
	int pos, x, y;
	extern void CanvasDrawPixel(int x1, int y1, int color, int alpha);
	#define NES_DISP_WIDTH      256
	#define NES_DISP_HEIGHT     240
		
	if (arr->memptr != PTR_WORK_FRAME)
	{
#ifdef _MSC_VER
		exit(-1);
#else
		while(1);
#endif
	}

	//NES_DISP_WIDTH * NES_DISP_HEIGHT * 2
	pos = arr->startpos + addr * 2;
	y = pos / (NES_DISP_WIDTH * 2);
	x = (pos - y * NES_DISP_WIDTH * 2) / 2;
	if ((pos - y * NES_DISP_WIDTH * 2) % 2 == 1)
	{
#ifdef _MSC_VER
		exit(-1);
#else
		while(1);
#endif
	}

	{
		const int __Gnbmp_height = 240; //tft lcd height
		const int __Gnbmp_width  = 240; //tft lcd width
		if (x < __Gnbmp_width && y < __Gnbmp_height)
		{
#ifndef USE_565
			WORD word = val;
			CanvasDrawPixel(x, y, RGB555toRGB(word), 0xff);
#else
			DWORD rgb;
			WORD word = val;
			rgb = RGB555toRGB(word);
			word = RGBtoRGB565(rgb);
			CanvasDrawPixel(x, y, word, 0xff);
#endif
		}
	}

#endif
}


















/*------------------------------*/

#ifdef _MSC_VER
static unsigned char Mem_Memory[2 * 1024 * 1024];
#else

#endif

void Mem_Init()
{
#ifdef _MSC_VER
	memset(Mem_Memory, 0, sizeof(Mem_Memory));
#else

#endif
}

void Mem_Read(unsigned char* pBuffer, int ReadAddr, int NumByteToRead)
{
#ifdef _MSC_VER
	memcpy(pBuffer, &Mem_Memory[ReadAddr], NumByteToRead);
#else

#endif
}

void Mem_Write(unsigned char* pBuffer, int WriteAddr, int NumByteToWrite)
{
#ifdef _MSC_VER
	memcpy(&Mem_Memory[WriteAddr], pBuffer, NumByteToWrite);
#else

#endif
}

/*------------------------------*/

